package com.tianji.learning.service.impl;

import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.constants.MqConstants;
import com.tianji.common.constants.RedisConstants;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BooleanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.DateUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.vo.SignResultVO;
import com.tianji.learning.mq.message.PointsMessage;
import com.tianji.learning.service.ISignRecordService;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.UUID;

@Service
@RequiredArgsConstructor
public class SignRecordServiceImpl implements ISignRecordService {

    private final StringRedisTemplate redisTemplate;

    private final RabbitMqHelper mqHelper;

    /**
     * 签到
     *
     * @return
     */
    @Override
    public SignResultVO signAchieve() {
        Long userId = UserContext.getUser();
        //获取当前日期
        LocalDate now = LocalDate.now();
        String sign = now.format(DateTimeFormatter.ofPattern(DateUtils.DEFAULT_MONTH_FORMAT_COMPACT));

        //获取key
        String key = RedisConstants.SIGN_RECORD_KEY_PREFIX + userId + ":" + sign;

        //获取offset
        int offset = (now.getDayOfMonth() - 1);

        //签到
        Boolean set = redisTemplate.opsForValue().setBit(key, offset, true);
        if (BooleanUtils.isTrue(set)) {
            throw new BizIllegalException("不能重复签到!!!");
        }

        //连续签到天数
        List<Long> longs = redisTemplate.opsForValue()
                .bitField(key, BitFieldSubCommands.create()
                        .get(BitFieldSubCommands.BitFieldType.unsigned(now.getDayOfMonth())).valueAt(0));
        Integer signDays = 0;
        if (CollUtils.isNotEmpty(longs)) {
            int num = longs.get(0).intValue();
            for (; (num & 1) == 1; num >>>= 1) {
                signDays++;
            }
        }

        //奖励积分
        Integer rewardPoints = 0;
        switch (signDays) {
            case 7:
                rewardPoints = 10;
                break;
            case 14:
                rewardPoints = 20;
                break;
            case 28:
                rewardPoints = 40;
                break;
        }
        SignResultVO vo = new SignResultVO();
        vo.setSignDays(signDays);
        vo.setRewardPoints(rewardPoints);

        //调用mq --- 发送签到消息
        mqHelper.send(
                MqConstants.Exchange.LEARNING_EXCHANGE,
                MqConstants.Key.SIGN_IN,
                PointsMessage.of(userId, vo.totalPoints())
        );
        return vo;
    }

    /**
     * 查询我的本月签到记录
     *
     * @return
     */
    @Override
    public Byte[] selectSignRecord() {
        Long userId = UserContext.getUser();

        //获取当前日期
        LocalDate now = LocalDate.now();

        String key = RedisConstants.SIGN_RECORD_KEY_PREFIX + userId + ":" + DateUtils.format(now, DateUtils.DEFAULT_MONTH_FORMAT_COMPACT);

        //获取num比特位
        List<Long> longs = redisTemplate.opsForValue()
                .bitField(key, BitFieldSubCommands.create()
                        .get(BitFieldSubCommands.BitFieldType.unsigned(now.getDayOfMonth())).valueAt(0));
        if (CollUtils.isEmpty(longs)) {
            return new Byte[0];
        }
        Long num = longs.get(0);
        Byte[] bytes = new Byte[now.getDayOfMonth()];
        for (int i = bytes.length - 1; i >= 0; i--) {
//            boolean b = (num & 1) == 1;
//            if (b){
//                bytes[i] = 1;
//            }else {
//                bytes[i] = 0;
//            }
            bytes[i] = (byte) (num & 1);
            num >>>= 1;
        }
        return bytes;
    }
}
